#include <sstream>
#include <iostream>

#include "holder.h"
#include "parser.h"
#include "decide.h"

using namespace std;
using namespace stock_trade;

int Holder::holderDay = 1;
float Holder::fee = 0.0006;
int Holder::minUnit = 100;

bool Holder::process(Transaction& transaction)
{
    DecideNumDynamic(transaction);
    if (transaction.action == BUY)
        return Buy(transaction);
    else if (transaction.action == SELL)
        return Sell(transaction);
    return false;
}

bool Holder::processFix(Transaction& transaction)
{
    DecideNumDynamic(transaction);
    if (transaction.action == BUY)
        return BuyFix(transaction);
    else if (transaction.action == SELL)
        return SellFix(transaction);
    return false;
}

bool Holder::BuyFix(Transaction& transaction)
{
    if (transaction.number <= 0)
    {
        failedLog.push_back(transaction);
        return false;
    }

    int number = transaction.number;
    if (number > 0)
    {
        validCash -= transaction.price * transaction.number * (1 + Holder::fee);
        //SendFIXMessage();
        log.push_back(transaction);
        cout << transaction.date << " " << transaction.time << " buy " << transaction.stock.name << " " << transaction.number << " " << transaction.price << endl;
        return true;
    }
    failedLog.push_back(transaction);
    return false;
}

bool Holder::SellFix(Transaction& transaction)
{
    if (transaction.number <= 0)
    {
        failedLog.push_back(transaction);
        return false;
    }

    int remainNumber = transaction.number;
    if (remainNumber > 0)
    {
        //SendFIXMessage();
        log.push_back(transaction);
        cout << transaction.date << " " << transaction.time << " sell " << transaction.stock.name << " " << transaction.number << " " << transaction.price << endl;
        return true;
    }
    failedLog.push_back(transaction);
    return false;
}

void Holder::DecideNumDynamic(Transaction& transaction)
{
    if (transaction.number == MAX_NUMBER)
    {
        if (transaction.action == BUY)
        {
            float number = validCash / transaction.price / (1 + Holder::fee);
            transaction.number = int(number) - int(number) % minUnit;
            validCash -= transaction.price * transaction.number * (1 + Holder::fee);
        }
        else if (transaction.action == SELL)
        {
            map<string, vector<Transaction> >::iterator i = stockHolder.find(transaction.stock.code);
            if (i == stockHolder.end())
                transaction.number = 0;

            float totalNumber = 0;
            for (vector<Transaction>::iterator j = i->second.begin(); j != i->second.end(); ++j)
            {
                if (transaction.date - j->date >= Holder::holderDay)
                    totalNumber += j->number;
            }
            transaction.number = int(totalNumber) - int(totalNumber) % minUnit;
        }
    }
}

bool Holder::Buy(Transaction& transaction)
{
    return buy(transaction);
}

bool Holder::buy(Transaction& transaction)
{
    if (transaction.number <= 0)
    {
        failedLog.push_back(transaction);
        return false;
    }

    int number = realBuy(transaction);
    if (number > 0)
    {
        transaction.number = number;
        cash -= transaction.price * transaction.number * (1 + Holder::fee);
        validCash = cash;
        map<string, vector<Transaction> >::iterator i = stockHolder.find(transaction.stock.code);
        if (i != stockHolder.end())
        {
            i->second.push_back(transaction);
        }
        else
        {
            vector<Transaction> vecTransaction;
            vecTransaction.push_back(transaction);
            stockHolder[transaction.stock.code] = vecTransaction;
        }
        log.push_back(transaction);
        cout << transaction.date << " " << transaction.time << " buy " << transaction.stock.name << " " << transaction.number << " " << transaction.price << endl;
        return true;
    }
    failedLog.push_back(transaction);
    return false;
}

bool Holder::Sell(Transaction& transaction)
{
    return sell(transaction);
}

bool Holder::sell(Transaction& transaction)
{
    if (transaction.number <= 0)
    {
        failedLog.push_back(transaction);
        return false;
    }

    int remainNumber = realSell(transaction);
    if (remainNumber > 0)
    {
        transaction.number = remainNumber;
        map<string, vector<Transaction> >::iterator i = stockHolder.find(transaction.stock.code);
        if (i == stockHolder.end())
            return false;
        for (vector<Transaction>::iterator j = i->second.begin(); j != i->second.end(); ++j)
        {
            if (transaction.date - j->date >= Holder::holderDay)
            {
                if (j->number >= remainNumber)
                {
                    j->number -= remainNumber;
                    break;
                }
                else
                {
                    remainNumber -= j->number;
                    j->number = 0;
                }
            }
        }
        cash += transaction.price * transaction.number * (1 - Holder::fee);
        validCash = cash;
        log.push_back(transaction);
        cout << transaction.date << " " << transaction.time << " sell " << transaction.stock.name << " " << transaction.number << " " << transaction.price << endl;
        return true;
    }
    failedLog.push_back(transaction);
    return false;
}
    
int Holder::realBuy(const Transaction& transaction)
{
    if (transaction.price <= 0)
        return 0;
    if (cash >= transaction.price * transaction.number * (1 + Holder::fee))
        return transaction.number;
    float realNumber = cash / transaction.price / (1 + Holder::fee);
    if (realNumber <= 0)
        return 0;
    return int(realNumber) - int(realNumber) % minUnit;
}

int Holder::realSell(const Transaction& transaction)
{
    map<string, vector<Transaction> >::iterator i = stockHolder.find(transaction.stock.code);
    if (i == stockHolder.end())
        return 0;

    int totalNumber = 0;
    for (vector<Transaction>::iterator j = i->second.begin(); j != i->second.end(); ++j)
    {
        if (transaction.date - j->date >= Holder::holderDay)
            totalNumber += j->number;
    }
    if (totalNumber < transaction.number)
    {
        return totalNumber;
    }
    return transaction.number;
}

float Holder::GetCurrentPrice(Stock stock, Date date, Time time)
{
    vector<Situation> vecSituation = Parser::ParseSituation(stock, date);
    if (vecSituation.size() == 0)
        return 0;
    float nowPrice = 0;
    for (vector<Situation>::iterator i = vecSituation.begin(); i != vecSituation.end(); ++i)
    {
        if (i->date == date && i->time < time)
            nowPrice = i->nowPrice;
        else
        {
            nowPrice = i->nowPrice;
            break;
        }
    }
    return nowPrice;
}

float Holder::GetCurrentValue(Date date, Time time)
{
    float allValue = cash;
    for (map<string, vector<Transaction> >::iterator i = stockHolder.begin(); i != stockHolder.end(); ++i)
        for (vector<Transaction>::iterator j = i->second.begin(); j != i->second.end(); ++j)
            allValue += GetCurrentPrice(j->stock, date, time) * j->number;
            //if (j->status == SUCCESS)
            //    allValue += GetCurrentPrice(j->stock, date, time) * j->number;
    return allValue;
}

void Holder::PrintFailedLog() const
{
    for (vector<Transaction>::const_iterator i = failedLog.begin(); i != failedLog.end(); ++i)
    {
        cout << "=====" << (*i).ToString() << endl;
    }
}

void Holder::Clean()
{
    cash = 0;
    validCash = 0;
    stockHolder.clear();
    log.clear();
    failedLog.clear();
    isComplete = false;
}
